/*
 * 文件名称:          PropertyNameMappingDeserialierFilter.java
 * 版权所有@ 2016——2017 无锡聆音科技有限公司，保留所有权利
 * 时间:             2016年7月27日 下午9:21:11
 */
package com.lingyin.json.deserializer;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;

/**
 *  json字符串转换为对象的时候，对json字符串的key值进行处理，以
 *  转变为需要对象的属性。如json字符中key值为abc，其值要转换为对象
 *  的xyz属性的值，则就需要用该过滤器进行处理
 * 
 * @项目        jsonlib
 * 
 * @作者:       关宏新
 * 
 * @日期:       2016年7月27日
 * 
 * @负责人:    关宏新
 * 
 * @负责小组:   聆音项目组
 * 
 */
public class PropertyNameMappingDeserialierFilter implements ExtraProcessor
{
    // 记录需要转换的映射类及相关属性关系。
    private Map<String, Map<String, String>> maps = new HashMap<String, Map<String, String>>();
    /**
     * 
     */
    public PropertyNameMappingDeserialierFilter()
    {
    }
    
    /**
     * 增加需要转换的属性定义
     * @param clazz 需要转换的class定义
     * @param sourcePropertyName 需要转换的原属性名
     * @param targetPropertyName 需要转换的新属性名
     */
    public PropertyNameMappingDeserialierFilter(Class<?> clazz, String sourcePropertyName, String targetPropertyName)
    {
        addPropertyMapping(clazz, sourcePropertyName, targetPropertyName);
    }
    
    /**
     * 增加需要转换的属性定义, 注意sourcePropertyName， targetPropertyName的长度必须一致。
     * @param clazz 需要转换的class定义
     * @param sourcePropertyName 需要转换的原属性名
     * @param targetPropertyName 需要转换的新属性名
     */
    public PropertyNameMappingDeserialierFilter(Class<?> clazz, String[] sourcePropertyName, String[] targetPropertyName)
    {
        addPropertyMapping(clazz, sourcePropertyName, targetPropertyName);
    }
    
    /**
     * 增加需要转换的属性定义
     * @param clazz 需要转换的class定义
     * @param sourcePropertyName 需要转换的原属性名
     * @param targetPropertyName 需要转换的新属性名
     * @return 原设置过的属性， 如果原没有设置过值，或clazz为null，则返回为null。
     */
    public String addPropertyMapping(Class<?> clazz, String sourcePropertyName, String targetPropertyName)
    {
        if (clazz == null)
        {
            return null;
        }
        String cn = clazz.getName();
        Map<String, String> temp = maps.get(cn);
        if (temp == null)
        {
            temp = new HashMap<String, String>();
            maps.put(cn, temp);
        }
        return temp.put(sourcePropertyName, targetPropertyName);
    }
    
    /**
     * 增加需要转换的属性定义,注意sourcePropertyName， targetPropertyName的长度必须一致。
     * @param clazz 需要转换的class定义
     * @param sourcePropertyName 需要转换的原属性名集合
     * @param targetPropertyName 需要转换的新属性名集合
     * @return 原设置过的属性， 如果原没有设置过值则返回为内容为null的数组，clazz为null，则返回为null。
     */
    public String[] addPropertyMapping(Class<?> clazz, String[] sourcePropertyName, String[] targetPropertyName)
    {
        if (clazz == null)
        {
            return null;
        }
        String cn = clazz.getName();
        Map<String, String> temp = maps.get(cn);
        if (temp == null)
        {
            temp = new HashMap<String, String>();
            maps.put(cn, temp);
        }
        int length = sourcePropertyName.length;
        String[] ret = new String[length];
        for (int i = 0; i < length; i ++)
        {
            ret[i] = temp.put(sourcePropertyName[i], targetPropertyName[i]);
        }
        return ret;
    }
    
    /**
     * 转换对象的属性名字
     * @param object 需要转换的对象
     * @param name 需要转换的属性名
     */
    public void processExtra(Object object, String name, Object value)
    {
        if (name == null || name.length() == 0 || object == null)
        {
            return; 
        }
        Class<?> cl = object.getClass();
        String clazz = cl.getName();
        Map<String, String> temp = maps.get(clazz);
        if (temp != null)
        {
            String ret = temp.get(name);
            if (ret != null)  // 转换为object的属性名。
            {
                try
                {
                    name = "set" + ret.substring(0, 1).toUpperCase() + ret.substring(1);
                    Method method = getMethod(cl, name, value);
                    if (method != null)
                    {
                        method.invoke(object, value);
                    }
                }
                catch(Exception e)
                {
                    e.printStackTrace();                    
                }
                return;
            }
        }
        return;
    }
    
    // 获取方法
    private Method getMethod(Class<?> cl, String name, Object value)
    {
        if (value == null)
        {
            Method[] methods = cl.getMethods();
            for (Method temp : methods)
            {
                // 找到一个就行
                if (temp.getName().equals(name) && temp.getParameterTypes().length == 1)
                {
                    return temp;
                }
            }
            return null;
        }
        
        try
        {
            Method method = cl.getMethod(name, value.getClass());            
            return method;
        }
        catch(Exception e)
        {
            try
            {
                Method method = cl.getMethod(name, getPrimitiveClass(value));            
                return method;
            }
            catch(Exception ee)
            {
                ee.printStackTrace();
            }
        }
        return null;
    }
     
    /**
     * @see     java.lang.Boolean#TYPE
     * @see     java.lang.Character#TYPE
     * @see     java.lang.Byte#TYPE
     * @see     java.lang.Short#TYPE
     * @see     java.lang.Integer#TYPE
     * @see     java.lang.Long#TYPE
     * @see     java.lang.Float#TYPE
     * @see     java.lang.Double#TYPE
     * @param value
     * @return
     */
    private Class<?> getPrimitiveClass(Object value)
    {
        if (value instanceof Boolean)
        {
            return Boolean.TYPE;
        }
        if (value instanceof Character)
        {
            return Character.TYPE;
        }
        if (value instanceof Byte)
        {
            return Byte.TYPE;
        }
        if (value instanceof Short)
        {
            return Short.TYPE;
        }
        if (value instanceof Integer)
        {
            return Integer.TYPE;
        }
        if (value instanceof Long)
        {
            return Long.TYPE;
        }
        if (value instanceof Float)
        {
            return Float.TYPE;
        }
        if (value instanceof Double)
        {
            return Double.TYPE;
        }
        return null;
    }

}
